#include"sock.hpp"
#include<sys/epoll.h>

#define MAX_NUM 64
namespace  ns_epoll
{
  class EpollSever
  {
    private:
        int epfd; //epoll_ctl 的第一个参数，表示当前有几个文件描述符存在epoll里面
        int listen_sock;
        uint16_t port;
    public:
        //构造
        EpollSever(uint16_t _port):port(_port)
        {}
        //初始化套接字
        void InitSever()
        {
          listen_sock=so_Sock::so_sock::Socket();
          so_Sock::so_sock::Bind(listen_sock,port);
          so_Sock::so_sock::Listen(listen_sock);
          //监听完毕，打印出来kankan
          std::cout<<"deBug test "<<" Listen sock "<<listen_sock<<std::endl;
          //初始化epoll函数的第一个参数
          if((epfd=epoll_create(256))<0)
          {
            //创建失败
            std::cout<<"epoll create fail"<<std::endl;
            exit(4);
          }
        }
        void AddEvent(int sock,uint16_t event)
        {
          struct epoll_event ev;
          ev.events=0;//初始化
          ev.events|=event;
          ev.data.fd=sock;

          //添加等待队列失败，继续等待
          if(epoll_ctl(epfd,EPOLL_CTL_ADD,sock,&ev)<0)
          {
            std::cout<<" epoll_ctl add fail "<<" sock "<<sock<<std::endl;
          }
        }
        void DeleteEvent(int sock)
        {
          if(epoll_ctl(epfd,EPOLL_CTL_DEL,sock,nullptr)<0)
          {
            std::cout<<" delete events fail "<<std::endl;
          }
        }
        //事件跑起来
        void Run()
        {
          //走到这里，至少有一个套接字，把套接字加到等待队列中，让epoll_wait “等”个文件描述符就绪
          AddEvent(listen_sock,EPOLLIN);
          int timeout=-1;
          struct epoll_event revs[MAX_NUM];//定义最大等待数
          //循环等待
          for(;;)
          {
            //返回值代表有几个事件准备好
            int num=epoll_wait(epfd,revs,MAX_NUM,timeout);
            if(num>0)
            {
                //说明等待成功,但是那个文件描述符就绪 不知道 遍历
                for(int i=0;i<MAX_NUM;i++)
                {
                   int sock = revs[i].data.fd;
                   if(revs[i].events & EPOLLIN)//读事件就绪
                   {
                     if(sock==listen_sock)
                     {
                       //连接事件就绪
                       struct sockaddr_in peer;
                       socklen_t len=sizeof(peer);
                       int sk=accept(sock,(struct sockaddr*)&peer,&len);
                       if(sk<0)
                       {
                         std::cout<<"accept fail "<<std::endl;
                         continue;
                       }
                       //得到一个新连接
                       std::cout<<"get a new link "<<std::endl;
                       AddEvent(sk,EPOLLIN);
                     }
                   //彻底就绪，直接读取文件
                   else 
                   {
                      char buffer[1024];
                      ssize_t  s=recv(sock,buffer,sizeof(buffer)-1,0);
                      if(s>0)
                      {
                        buffer[s]=0;
                        std::cout<<buffer<<std::endl;
                      }
                      else 
                      {
                        std::cout<<"Client close "<<std::endl;
                        close(sock);
                        //移除这个套接字在epfd中
                        DeleteEvent(sock);
                      }
                   }
                }
                else if(revs[i].events&EPOLLOUT)
                {
                  // todo 
                }
                else 
                {
                  //do some thing 
                }
              }
            }
            else if(num==0)
            {
              std::cout<<" time out"<<std::endl;
            }
            else 
            {
              std::cout<<" epoll error "<<std::endl;
            }
          }

        }
       ~EpollSever()
       {
         if(listen_sock>=0)close(listen_sock);
         if(epfd>=0)close(epfd);
       }

  };
}
